﻿using CQRSFramework.Events;
using CQRSFramework.Infrustructures;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace CQRSFramework.Commands
{
    public class EventMailBox
    {
        public string AggregateRootId { get; set; }
        public bool Exited => false;
        public int CurrentStatus;
        private readonly IProcessingEventHandler _handler;
        private ConcurrentQueue<ProcessingEvent> _messageQueue = new ConcurrentQueue<ProcessingEvent>();
        private static readonly object obj = new object();

        public EventMailBox(string aggregateRootId, IProcessingEventHandler handler)
        {
            AggregateRootId = aggregateRootId;
            _handler = handler;
        }

        public void Enqueue(ProcessingEvent message)
        {
            if (Exited)
                return;
            _messageQueue.Enqueue(message);
            TryExecute();
        }

        private void TryExecute()
        {
            if (this.Exited)
                return;
            int status = Interlocked.CompareExchange(ref this.CurrentStatus, Status.EXECUTING, Status.WAITING);
            if (status == Status.WAITING)
            {
                lock (obj)
                {
                    ProcessingEvent evnt;
                    if (_messageQueue.TryDequeue(out evnt))
                    {

                        _handler.Handle(evnt);
                    }

                    if (this.Exited)
                    {
                        Interlocked.Exchange(ref this.CurrentStatus, Status.EXITED);
                    }
                    else
                    {
                        Interlocked.CompareExchange(ref CurrentStatus, Status.WAITING, Status.EXECUTING);
                        if (_messageQueue.Count > 0)
                        {
                            Task.Factory.StartNew(TryExecute);
                        }
                    }
                }
            }
        }
    }
}
